package com.dingreading.cloud.soms.controller;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.dto.LoginDataDto;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.excel.ExcelHandler;
import com.dingreading.cloud.soms.dto.MemberClueDto;
import com.dingreading.cloud.soms.dto.MembersDto;
import com.dingreading.cloud.soms.dto.vo.MemberVO;
import com.dingreading.cloud.soms.entity.*;
import com.dingreading.cloud.soms.mapper.MembersMapper;
import com.dingreading.cloud.soms.service.*;
import com.dingreading.cloud.soms.util.CmorderUtil;
import com.dingreading.cloud.soms.util.FollowUtil;
import com.dingreading.cloud.soms.util.LoginInfoUtil;
import com.dingreading.cloud.soms.util.MemberBeanUtil;
import com.dingreading.cloud.soms.util.redis.RedisService;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/front/members")
@Api(tags = "门店-会员管理")
public class FrontMembersController {

    @Resource
    protected MembersService membersService;
    @Resource
    protected MemberFollowService memberFollowService;
    @Resource
    protected StaffService staffService;
    @Resource
    protected CmordersService cmordersService;
    @Resource
    protected MemberChannelService channelService;
    @Resource
    protected StoreProjectsService storeProjectsService;
    @Resource
    protected StoreProductsService storeProductsService;
    @Resource
    protected StoreProductLogsService productLogsService;
    @Resource
    protected CmservicesService cmservicesService;
    @Resource
    protected StoresService storesService;
    @Resource
    protected MembersMapper membersMapper;
    @Resource
    protected RedisService redisService;


    @ApiOperation(value = "分页，根据门店uid、姓名或手机号获取体验会员")
    @PostMapping(value = "/getMemberListByType", produces = "application/json; charset=UTF-8")
    public R<Object> getMemberListByType(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工姓名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "姓名或手机号") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "状态 1.启用 0.禁用") @RequestParam(value = "enabled", required = false) Integer enabled,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate,
            @ApiParam(value = "跟进人uid") @RequestParam(value = "followStaffUid", required = false) String followStaffUid,
            @ApiParam(value = "幼儿园：小:-3，中:-2，大-1；小学：一:1，二:2，三:3，四:4，五:5，六:6；初中：初一:7，初二:8；未知:0")
            @RequestParam(value = "grade", required = false) Integer grade,
            @ApiParam(value = "会员类型 1.无服务会员 2.体验会员 3.正式会员 4.过期会员") @RequestParam(value = "memberType", required = false) Integer memberType,
            @ApiParam(value = "客户来源") @RequestParam(value = "customSource", required = false) String customSource,
            @ApiParam(value = "异业渠道") @RequestParam(value = "channelUid", required = false) String channelUid
    ) {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        boolean managerOrAdvisor = false;
        if (AccountUtil.isManagerOrAdvisor(loginDto.getStoreRoles())) {
            managerOrAdvisor = true;
        }

        if (null != memberType && (memberType < 1 || memberType > 4))
            return R.fail("会员类型错误");

//        Integer pageValue = pageUtil.getPageValue();
//        String redisKey = RedisParam.STORE_MEMBERS + storeUid;
//        PageDto<MembersDto> page = null;
//        String json = (String) redisService.get(redisKey);
//        if (pageValue.equals(1) && StringUtils.isNotBlank(json) && StringUtils.isBlank(keyword) && StringUtils.isBlank(beginDate)
//                && StringUtils.isBlank(endDate) && StringUtils.isBlank(followStaffUid) && null == grade && null == memberType
//                && StringUtils.isBlank(customSource) && StringUtils.isBlank(channelUid)) {
//            // redis只获取首页无条件的查询结果
//            page = JSONObject.parseObject(json, PageDto.class);
//        } else {
//            page = membersService.getMemberListByType(pageUtil, managerOrAdvisor, storeUid, keyword, enabled, beginDate, endDate,
//                    followStaffUid, grade, memberType, customSource, channelUid);
        // redis只保存首页无条件的查询结果
//            if (page != null && pageValue.equals(1) && StringUtils.isBlank(keyword) && StringUtils.isBlank(beginDate)
//                    && StringUtils.isBlank(endDate) && StringUtils.isBlank(followStaffUid) && null == grade
//                    && null == memberType && StringUtils.isBlank(customSource) && StringUtils.isBlank(channelUid)) {
//                json = JSONObject.toJSONString(page);
        // 缓存2小时
//                redisService.set(redisKey, json, 7200);
//            }
//        }

        PageDto<MembersDto> page = membersService.getMemberListByType(pageUtil, managerOrAdvisor, storeUid, keyword, enabled, beginDate, endDate,
                followStaffUid, grade, memberType, customSource, channelUid);
        return R.ok(page);
    }

    @ApiOperation(value = "根据门店uid、姓名或手机号获取会员")
    @PostMapping(value = "/getMemberOptions", produces = "application/json; charset=UTF-8")
    public R<Object> getMemberOptions(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工姓名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "姓名或手机号") @RequestParam(value = "keyword") String keyword,
            @ApiParam(value = "状态 1.启用 0.禁用") @RequestParam(value = "enabled", required = false) Integer enabled
    ) {
        if (StringUtils.isBlank(keyword))
            return R.fail("查询关键字不能为空");

        if (StringUtil.isChinese(keyword)) {
            if (keyword.length() < 2)
                return R.fail("名字至少填写2位");
        } else {
            if (StringUtils.isNumeric(keyword)) {
                if (keyword.length() < 4)
                    return R.fail("手机号至少填写4位");
            }
        }

        List<Members> list = membersService.getByStoreUidAndKeyword(corpUid, storeUid, keyword, enabled);
        return R.ok(list);
    }

    @ApiOperation(value = "获取会员详情")
    @PostMapping(value = "/getMemberInfo", produces = "application/json; charset=UTF-8")
    public R<Object> getMemberInfo(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工姓名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "uid") String uid
    ) {
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        Members data = membersService.getMemberInfo(loginDto.getCorpUid(), uid);
        if (data != null) {
            // 不是店长或顾问，隐藏手机号码
            boolean managerOrAdvisor = AccountUtil.isManagerOrAdvisor(loginDto.getStoreRoles());
            if (!managerOrAdvisor) {
                // 隐藏手机号码
                String mob = data.getMob();
                if (StringUtils.isNotBlank(mob) && mob.length() == 11) {
                    data.setMob(RegularUtil.hidePhone(mob));
                }
                // 隐藏微信号
                String wxName = data.getWxName();
                if (StringUtils.isNotBlank(wxName)) {
                    data.setWxName(RegularUtil.hideWxName(wxName, 2, 2));
                }
            }
        }
        return R.ok(data);
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "新增/编辑会员信息")
    @PostMapping(value = "/newBean", produces = "application/json; charset=UTF-8")
    public R<Object> newBean(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "uid", required = false) String uid,
            @ApiParam(value = "姓名") @RequestParam(value = "fullName") String fullName,
            @ApiParam(value = "幼儿园：小:-3，中:-2，大-1；小学：一:1，二:2，三:3，四:4，五:5，六:6；初中：初一:7，初二:8；未知:0")
            @RequestParam(value = "grade") Integer grade,
            @ApiParam(value = "手机号/微信号") @RequestParam(value = "mob") String mob,
            @ApiParam(value = "生日") @RequestParam(value = "dateOfBirth", required = false) String dateOfBirth,
            @ApiParam(value = "性别 女:0，男:1，未知:2") @RequestParam(value = "sex", required = false) Integer sex,
            @ApiParam(value = "学校名称") @RequestParam(value = "schoolName", required = false) String schoolName,
            @ApiParam(value = "小区名称") @RequestParam(value = "houseName", required = false) String houseName,
            @ApiParam(value = "客户来源：地推:DT、异业:YY、转介绍:ZJ、自然到访:ZR、其他:QT")
            @RequestParam(value = "customSource", required = false) String customSource,
            @ApiParam(value = "客户来源备注") @RequestParam(value = "customSourceRemark", required = false) String customSourceRemark,
            @ApiParam(value = "异业渠道uid") @RequestParam(value = "channelUid", required = false) String channelUid,
            @ApiParam(value = "异业渠道名称") @RequestParam(value = "channelName", required = false) String channelName,
            @ApiParam(value = "转介绍人uid") @RequestParam(value = "refererMemberUid", required = false) String refererMemberUid,
            @ApiParam(value = "转介绍人姓名") @RequestParam(value = "refererMemberName", required = false) String refererMemberName,
            @ApiParam(value = "市场人员uid") @RequestParam(value = "refererStaffUid", required = false) String refererStaffUid,
            @ApiParam(value = "市场人员姓名") @RequestParam(value = "refererStaffName", required = false) String refererStaffName
    ) throws Exception {
        // 获取员工信息
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();
        String nickName = loginDto.getNickName();
        long storeId = loginDto.getCurrentStoreId();

        if (StringUtils.isBlank(fullName))
            return R.fail("请填写会员姓名");
        fullName = StringUtils.deleteWhitespace(fullName);
        if (fullName.length() < 2)
            return R.fail("会员姓名至少填写2位");
        if (!StringUtil.isChinese(fullName) && !RegularUtil.isValidPhoneNumber(fullName))
            return R.fail("请填写正确的会员姓名");
        if (null == grade)
            return R.fail("请选择年级");
        if (StringUtils.isBlank(mob))
            return R.fail("请填写手机号或微信号");
        String wxName = "";
        if (StringUtils.isNotBlank(mob)) {
            if (StringUtil.isInteger(mob)) {
                // 是手机号
                if (mob.length() != 11)
                    return R.fail("请填写正确的手机号");

                Members exMember = membersService.haveCorpUidAndMobAndFullName(corpUid, mob, fullName, uid);
                if (null != exMember) {
                    if (null != exMember.getValidStatus() && exMember.getValidStatus().equals(1))
                        return R.fail("手机号和姓名已被注册会员");
                    else
                        return R.fail("手机号和姓名已被注册线索");
                }
            } else {
                // 是微信号
                if (mob.length() < 6)
                    return R.fail("请填写正确的微信号");
                wxName = mob;
                mob = "";

                Members exMember = membersService.haveCorpUidAndWxNameAndFullName(corpUid, wxName, fullName, uid);
                if (null != exMember) {
                    if (null != exMember.getValidStatus() && exMember.getValidStatus().equals(1))
                        return R.fail("微信号和姓名已被注册会员");
                    else
                        return R.fail("微信号和姓名已被注册线索");
                }
            }
        }

        String staffPubPhone = "";
        String staffPriPhone = "";
        String staffNickName = "";
        String staffFullName = "";
        if (StringUtils.isNotBlank(refererStaffUid)) {
            Staff staff = staffService.getByUid(refererStaffUid);
            if (null == staff) return R.fail("市场人员获取失败");

            staffFullName = staff.getFullName();
            if (StringUtils.isBlank(staffFullName))
                return R.fail("请先完善市场人员的全名");
            staffPriPhone = staff.getPriPhone();
            staffPubPhone = staff.getPubPhone();
            staffNickName = staff.getNickName();
        }

        Members data = null;
        // 门店角色
        String source = EnumType.Source.STORE.getName();
        String content = "门店录入";
        String followType = EnumType.Follow.SAVE.getType();
        String followTypeName = EnumType.Follow.SAVE.getName();

        if (StringUtils.isNotBlank(uid)) {
            data = membersService.getByUid(storeUid, uid);
            if (null == data)
                return R.fail("会员信息获取失败");
            if (null != data.getSource() && (data.getSource().equals(EnumType.Source.XCX.getName()) || data.getSource().equals(EnumType.Source.MARKET.getName()))) {
                String sourceName = "";
                if (data.getSource().equals(EnumType.Source.XCX.getName()))
                    sourceName = "小程序录入";
                else if (data.getSource().equals(EnumType.Source.MARKET.getName()))
                    sourceName = "市场录入";
                // 录入来源是小程序,不能修改客户来源和异业渠道
                String dataCustomSource = data.getCustomSource();
                if ((StringUtils.isNotBlank(dataCustomSource) && !dataCustomSource.equals(customSource)) || (StringUtils.isBlank(dataCustomSource) && StringUtils.isNotBlank(customSource)))
                    return R.fail(sourceName + ",不能修改客户来源");
                String dataChannelUid = data.getChannelUid();
                if ((StringUtils.isNotBlank(dataChannelUid) && !dataChannelUid.equals(channelUid)) || (StringUtils.isBlank(dataChannelUid) && StringUtils.isNotBlank(channelUid)))
                    return R.fail(sourceName + ",不能修改渠道");
                String dataRefererStaffUid = data.getRefererStaffUid();
                if ((StringUtils.isNotBlank(dataRefererStaffUid) && !dataRefererStaffUid.equals(refererStaffUid)) || (StringUtils.isBlank(dataRefererStaffUid) && StringUtils.isNotBlank(refererStaffUid)))
                    return R.fail(sourceName + ",不能修改市场人员");
            }
            followType = EnumType.Follow.UPDATE.getType();
            followTypeName = EnumType.Follow.UPDATE.getName();
            content = "";
        }
        // 判断是否店长
        boolean storeManager = AccountUtil.isStoreManager(loginDto.getStoreRoles());
        // 跟进时间
        Date followTime = DateUtil.getNowDatetime();
        data = MemberBeanUtil.newMember(data, storeManager, corpUid, storeUid, storeId, storeName, fullName,
                mob, wxName, sex, grade, dateOfBirth,
                customSource, customSourceRemark, channelUid, channelName, refererMemberUid, refererMemberName,
                refererStaffUid, staffFullName, staffNickName, staffPubPhone, staffPriPhone,
                staffUid, staffName, nickName, followTime, schoolName, houseName, source);
        membersMapper.insertOrUpdate(data, false);

        //TODO 创建跟进记录
        MemberFollow follow = FollowUtil.newFollow(corpUid, storeUid, storeName, loginDto.getStaffUid(),
                loginDto.getFullName(), data.getUid(), data.getMemberName(),
                followType, followTypeName, content, source, followTime);
        memberFollowService.saveOrUpdate(follow);

        // 返回会员基本信息
        Members info = membersService.getMemberInfo(corpUid, data.getUid());

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        // 清空门店会员缓存
        redisService.setNullLike(RedisParam.STORE_MEMBERS);
        return R.ok(info);
    }

    @ApiOperation(value = "更新会员的启用/禁用")
    @PostMapping(value = "/updateEnabled", produces = "application/json; charset=UTF-8")
    public R<Object> updateEnabled(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "uid") String uid,
            @ApiParam(value = "1.启用 0.禁用") @RequestParam(value = "enabled") int enabled
    ) {
        Members memberInfo = membersService.getByUid(storeUid, uid);
        if (null == memberInfo) return R.fail("会员信息获取失败");

        Date time = DateUtil.getNowDatetime();
        boolean l = membersService.updateEnabled(storeUid, uid, enabled, staffUid, staffName, time);
        if (!l) return R.fail("操作失败");

        //TODO 创建跟进记录
        String str = enabled == 0 ? "禁用" : "启用";
        MemberFollow follow = FollowUtil.newFollow(
                corpUid, storeUid, storeName, staffUid, staffName, memberInfo.getUid(), memberInfo.getMemberName(),
                EnumType.Follow.UPDATE.getType(), EnumType.Follow.UPDATE.getName(), "会员被 " + str,
                null, time
        );
        memberFollowService.saveOrUpdate(follow);
        // 更新会员的最后跟进信息
        membersService.updateLastFollowInfo(storeUid, memberInfo.getUid(), follow.getUid(), time);
        return R.ok();
    }

    @Deprecated
    @ApiOperation(value = "按姓名和手机号获取会员")
    @PostMapping(value = "/getByNameAndPhone")
    public R<Object> getByNameAndPhone(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "姓名或手机号") @RequestParam(value = "keyword") String keyword
    ) {
        if (StringUtils.isBlank(keyword))
            return R.fail("请填写姓名或手机号");

        if (StringUtil.isChinese(keyword)) {
            if (keyword.length() < 2)
                return R.fail("名字至少填写2位");
        } else {
            if (StringUtils.isNumeric(keyword)) {
                if (keyword.length() < 4)
                    return R.fail("手机号至少填写4位");
            }
        }

        List<Members> list = membersService.getByMemberNameAndFullNameAndMob(storeUid, keyword);
        if (CollectionUtils.isNotEmpty(list))
            return R.ok(list);
        else
            return R.fail(0, "未查询到该会员");
    }

    @Deprecated
    @ApiOperation(value = "根据uid获取信息")
    @PostMapping(value = "/getByUid", produces = "application/json; charset=UTF-8")
    public R<Object> getByUid(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "memberUid") String memberUid
    ) {
        Members data = membersService.getByUid(storeUid, memberUid);

        return R.ok(data);
    }

    @ApiOperation(value = "获取公司下的会员列表")
    @PostMapping(value = "/getCorpMembers")
    public R<Object> getCorpMembers(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "姓名或手机号") @RequestParam(value = "keyword") String keyword
    ) {
        if (StringUtils.isBlank(keyword))
            return R.fail("查询关键字不能为空");
        if (keyword.length() < 2)
            return R.fail("查询关键字至少填写2位");

        List<JSONObject> list = membersService.getCorpMembers(corpUid, storeUid, keyword);
        if (CollectionUtils.isNotEmpty(list))
            return R.ok(list);
        else
            return R.fail(0, "未查询到该会员");
    }

    @ApiOperation(value = "线索会员分页")
    @PostMapping(value = "/getMemberClueList", produces = "application/json; charset=UTF-8")
    public R<Object> getMemberClueList(
            HttpServletRequest request,
            @ApiParam(value = "分页公共类") PageUtil pageUtil,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "姓名或手机号") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "状态 1.启用 0.禁用") @RequestParam(value = "enabled", required = false) Integer enabled,
            @ApiParam(value = "开始日期") @RequestParam(value = "beginDate", required = false) String beginDate,
            @ApiParam(value = "结束日期") @RequestParam(value = "endDate", required = false) String endDate,
            @ApiParam(value = "跟进人uid") @RequestParam(value = "followStaffUid", required = false) String followStaffUid,
            @ApiParam(value = "幼儿园：小:-3，中:-2，大-1；小学：一:1，二:2，三:3，四:4，五:5，六:6；初中：初一:7，初二:8；未知:0")
            @RequestParam(value = "grade", required = false) Integer grade,
            @ApiParam(value = "客户来源") @RequestParam(value = "customSource", required = false) String customSource,
            @ApiParam(value = "异业渠道") @RequestParam(value = "channelUid", required = false) String channelUid,
            @ApiParam(value = "市场人员uid") @RequestParam(value = "refererStaffUid", required = false) String refererStaffUid,
            @ApiParam(value = "线索状态 -1.无效 1.有效") @RequestParam(value = "validStatus", required = false) Integer validStatus
    ) {
        // 获取员工信息
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();

        // 获取员工角色
        int role = AccountUtil.isMarketStaff(loginDto.getStoreRoles());
        String queryStaffUid = "";
        String queryStoreUid = "";
        if (role == 1 || role == 2) {
            // 店长/店助只能看本门店录入的数据
            queryStoreUid = loginDto.getCurrentStoreUid();
        } else if (role == 3) {
            // 市场组长
            queryStoreUid = loginDto.getCurrentStoreUid();
        } else if (role == 4) {
            // 市场人员只能看自己录入的数据
            queryStoreUid = loginDto.getCurrentStoreUid();
            queryStaffUid = staffUid;
        } else {
            // 店助或导读只能看本门店自己录入的数据
            queryStoreUid = loginDto.getCurrentStoreUid();
            queryStaffUid = staffUid;
        }

        Page<MemberClueDto> page = membersService.getMemberClueList(
                pageUtil, queryStoreUid, keyword, enabled, beginDate, endDate, followStaffUid, grade, customSource,
                channelUid, refererStaffUid, queryStaffUid, validStatus
        );
        PageBeanDto dto = new PageBeanDto();
        dto.setTotal(page.getTotalRow());
        dto.setList(page.getRecords());
        return R.ok(dto);
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "新增/编辑会员信息")
    @PostMapping(value = "/newBeanByMarket", produces = "application/json; charset=UTF-8")
    public R<Object> newBeanByMarket(
            HttpServletRequest request,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "uid", required = false) String uid,
            @ApiParam(value = "姓名") @RequestParam(value = "fullName") String fullName,
            @ApiParam(value = "幼儿园：小:-3，中:-2，大-1；小学：一:1，二:2，三:3，四:4，五:5，六:6；初中：初一:7，初二:8；未知:0")
            @RequestParam(value = "grade") Integer grade,
            @ApiParam(value = "手机号") @RequestParam(value = "mob") String mob,
            @ApiParam(value = "生日") @RequestParam(value = "dateOfBirth", required = false) String dateOfBirth,
            @ApiParam(value = "性别 女:0，男:1，未知:2") @RequestParam(value = "sex", required = false) Integer sex,
            @ApiParam(value = "学校名称") @RequestParam(value = "schoolName", required = false) String schoolName,
            @ApiParam(value = "小区名称") @RequestParam(value = "houseName", required = false) String houseName,
            @ApiParam(value = "客户来源：地推:DT、异业:YY、转介绍:ZJ、自然到访:ZR、其他:QT")
            @RequestParam(value = "customSource", required = false) String customSource,
            @ApiParam(value = "客户来源备注") @RequestParam(value = "customSourceRemark", required = false) String customSourceRemark,
            @ApiParam(value = "异业渠道uid") @RequestParam(value = "channelUid", required = false) String channelUid,
            @ApiParam(value = "异业渠道名称") @RequestParam(value = "channelName", required = false) String channelName,
            @ApiParam(value = "转介绍人uid") @RequestParam(value = "refererMemberUid", required = false) String refererMemberUid,
            @ApiParam(value = "转介绍人姓名") @RequestParam(value = "refererMemberName", required = false) String refererMemberName,
            @ApiParam(value = "市场人员uid") @RequestParam(value = "refererStaffUid", required = false) String refererStaffUid,
            @ApiParam(value = "市场人员姓名") @RequestParam(value = "refererStaffName", required = false) String refererStaffName
    ) throws Exception {
        // 获取员工信息
        R<Object> r = LoginInfoUtil.getLoginDto(request);
        if (R.isError(r)) return r;
        LoginDataDto loginDto = (LoginDataDto) r.getData();
        String nickName = loginDto.getNickName();

        if (StringUtils.isBlank(fullName))
            return R.fail("请填写会员姓名");
        if (fullName.length() < 2)
            return R.fail("会员姓名至少填写2位");
        fullName = fullName.trim();
        if (!StringUtil.isChinese(fullName) && !RegularUtil.isValidPhoneNumber(fullName))
            return R.fail("请填写正确的会员姓名");
        if (StringUtils.isBlank(mob))
            return R.fail("请填写手机号或微信号");
        if (null == grade)
            return R.fail("请选择年级");

        Stores stores = storesService.getByUid(storeUid);
        if (null == stores)
            return R.fail("门店获取失败");
        Long storeId = stores.getId();

        String wxName = "";
        if (StringUtil.isInteger(mob)) {
            // 是手机号
            if (mob.length() != 11)
                return R.fail("请填写正确的手机号");

            Members exMember = membersService.haveCorpUidAndMobAndFullName(corpUid, mob, fullName, uid);
            if (null != exMember) {
                if (null != exMember.getValidStatus() && exMember.getValidStatus().equals(1))
                    return R.fail("手机号和姓名已被注册会员");
                else
                    return R.fail("手机号和姓名已被注册线索");
            }
        } else {
            // 是微信号
            if (mob.length() < 6)
                return R.fail("请填写正确的微信号");
            wxName = mob;
            mob = "";

            Members exMember = membersService.haveCorpUidAndWxNameAndFullName(corpUid, wxName, fullName, uid);
            if (null != exMember) {
                if (null != exMember.getValidStatus() && exMember.getValidStatus().equals(1))
                    return R.fail("微信号和姓名已被注册会员");
                else
                    return R.fail("微信号和姓名已被注册线索");
            }
        }

        String staffPubPhone = "";
        String staffPriPhone = "";
        String staffNickName = "";
        String staffFullName = "";
        if (StringUtils.isNotBlank(refererStaffUid)) {
            Staff staff = staffService.getByUid(refererStaffUid);
            if (null == staff)
                return R.fail("市场人员获取失败");
            staffFullName = staff.getFullName();
            if (StringUtils.isBlank(staffFullName))
                return R.fail("请先完善市场人员的全名");
            staffPriPhone = staff.getPriPhone();
            staffPubPhone = staff.getPubPhone();
            staffNickName = staff.getNickName();
        }

        Members data = null;
        // 市场角色
        String source = EnumType.Source.MARKET.getName();
        String content = "线索录入";
        String followType = EnumType.Follow.SAVE.getType();
        String followTypeName = EnumType.Follow.SAVE.getName();

        if (StringUtils.isNotBlank(uid)) {
            data = membersService.getByUid(null, uid);
            if (null == data)
                return R.fail("会员信息获取失败");
            if (data.getValidStatus().equals(1))
                return R.fail("有效线索，不能操作");
            if (null != data.getSource()) {
                if (data.getSource().equals(EnumType.Source.XCX.getName())) {
                    return R.fail("小程序录入,不能操作");
                }
            }

            content = "";
            followType = EnumType.Follow.UPDATE.getType();
            followTypeName = EnumType.Follow.UPDATE.getName();
        }
        Date followTime = DateUtil.getNowDatetime();
        String lastFollowUid = KitUtil.getUuid();
        data = MemberBeanUtil.newMemberByMarket(
                data, corpUid, storeUid, storeId, storeName, fullName, mob, wxName, sex, grade, dateOfBirth,
                customSource, customSourceRemark, channelUid, channelName, refererMemberUid, refererMemberName,
                refererStaffUid, staffFullName, staffNickName, staffPubPhone, staffPriPhone,
                staffUid, staffName, nickName, followTime, schoolName, houseName, source, lastFollowUid
        );
        membersMapper.insertOrUpdate(data, false);

        // 创建跟进记录
        MemberFollow follow = FollowUtil.newFollow(
                lastFollowUid, corpUid, storeUid, storeName, staffUid, staffName, data.getUid(), data.getMemberName(),
                followType, followTypeName, content, source, followTime
        );
        memberFollowService.saveOrUpdate(follow);

        // 返回会员基本信息
        Members info = membersService.getMemberInfo(corpUid, data.getUid());

        // 清空门店缓存
        redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
        redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
        // 清空门店会员缓存
        redisService.setNullLike(RedisParam.STORE_MEMBERS);
        return R.ok(info);
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "设置会员线索状态")
    @PostMapping(value = "/updateValidStatus", produces = "application/json; charset=UTF-8")
    public R<Object> updateValidStatus(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "uid") String uid,
            @ApiParam(value = "线索状态 -1.无效 1.有效") @RequestParam(value = "validStatus") int validStatus,
            @ApiParam(value = "备注") @RequestParam(value = "remark", required = false) String remark
    ) throws Exception {
        if (validStatus != 1 && validStatus != -1)
            return R.fail("状态错误");

        Members data = membersService.getByUid(null, uid);
        if (null == data)
            return R.fail("会员信息获取失败");

        if (validStatus == -1) {
            if (StringUtils.isBlank(remark))
                return R.fail("请填写备注");
            long orderNum = cmordersService.getMemberNewOrderNum(storeUid, uid);
            if (orderNum > 0)
                return R.fail("会员有正价订单，不能设置为无效线索");
        }

        String memberUid = data.getUid();
        String memberName = data.getMemberName();

        // 首次设为有效，判断渠道的产品uid创建订单
        Cmorders cmorders = null;
        List<Cmservices> cmservicesList = new ArrayList<>();
        if (data.getValidStatus().equals(0) && validStatus == 1 && StringUtils.isNotBlank(data.getChannelUid())) {
            Staff staff = staffService.getByUid(staffUid);
            if (staff == null)
                return R.fail("录入员工获取失败员工信息：" + staffName);
            MemberChannel channel = channelService.getByUid(data.getChannelUid());
            if (null == channel)
                return R.fail("渠道获取失败");
            // 根据渠道下的产品包，创建会员订单和服务
            if (StringUtils.isNotBlank(channel.getProductUid())) {
                cmorders = newMemberOrderAndServices(cmservicesList, corpUid, storeUid, storeName, memberUid, memberName,
                        staff, staffUid, staffName, channel.getProductUid(), "来于渠道产品包");
            }
        }

        boolean l = membersService.updateValidStatus(storeUid, uid, validStatus, staffUid, staffName);
        if (!l)
            throw new DescribeException("操作失败");

        Date followTime = DateUtil.getNowDatetime();
        //TODO 创建跟进记录
        String content = validStatus == 1 ? "有效会员" : "无效线索";
        if (StringUtils.isNotBlank(remark))
            content += "，备注：" + remark;
        MemberFollow follow2 = FollowUtil.newFollow(corpUid, storeUid, storeName, staffUid, staffName, memberUid, memberName,
                EnumType.Follow.MEMBER_VALID.getType(), EnumType.Follow.MEMBER_VALID.getName(),
                "设置为 " + content, null, followTime);
        memberFollowService.saveOrUpdate(follow2);
        // 更新会员的最后跟进信息
        membersService.updateLastFollowInfo(storeUid, data.getUid(), follow2.getUid(), followTime);

        // 首次设为有效，保存会员订单和服务信息
        if (data.getValidStatus().equals(0) && validStatus == 1 && StringUtils.isNotBlank(data.getChannelUid())) {
            if (null != cmorders && CollectionUtils.isNotEmpty(cmservicesList)) {
                cmordersService.saveOrUpdate(cmorders);
                cmservicesService.saveOrUpdateBatch(cmservicesList);
                // 创建跟进记录
                String followType = EnumType.Follow.NEW_ORDER.getType();
                String followTypeName = EnumType.Follow.NEW_ORDER.getName();
                MemberFollow follow1 = FollowUtil.newFollow(corpUid, storeUid, storeName, staffUid, staffName,
                        memberUid, memberName, followType, followTypeName, "订单号：" + cmorders.getOrderCode(),
                        cmorders.getOrderCode(), followTime);
                memberFollowService.saveOrUpdate(follow1);
            }
        }

        if (validStatus == 1) {
            // 清空门店缓存
            redisService.setNullLike(RedisParam.STORE_DATA + storeUid);
            redisService.setNullLike(RedisParam.STORE_DATA_SERVICE + storeUid);
            redisService.setNullLike(RedisParam.STORE_DATA_KINDS + storeUid);
            // 清空门店会员缓存
            redisService.setNullLike(RedisParam.STORE_MEMBERS);
        }

        return R.ok();
    }

    @Transactional(rollbackFor = DescribeException.class)
    @ApiOperation(value = "删除线索会员")
    @PostMapping(value = "/dropClueMember", produces = "application/json; charset=UTF-8")
    public R<Object> dropClueMember(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid") @RequestParam(value = "uid") String uid
    ) throws Exception {
        Members data = membersService.getByUid(null, uid);
        if (null == data) return R.fail("会员信息获取失败");

        if (data.getSource().equals(EnumType.Source.STORE.getName()))
            return R.fail("门店录入，不能操作");
        if (data.getSource().equals(EnumType.Source.XCX.getName()))
            return R.fail("小程序录入，不能操作");

        if (data.getValidStatus().equals(1))
            return R.fail("已是有效会员，不能操作");

        long orderNum = cmordersService.getMemberNewOrderNum(data.getStoreUid(), uid);
        if (orderNum > 0) return R.fail("会员有正价订单，不能操作");

        long l = membersService.dropClueMember(data.getStoreUid(), uid);
        if (l <= 0)
            return R.failDel();
        return R.ok();
    }

    @ApiOperation(value = "导出会员信息")
    @PostMapping(value = "/exportMemberList", produces = "application/vnd.ms-excel;charset=UTF-8")
    public void exportMemberList(
            HttpServletRequest request,
            HttpServletResponse response,
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "姓名或手机号") @RequestParam(value = "keyword", required = false) String keyword,
            @ApiParam(value = "跟进人uid") @RequestParam(value = "followStaffUid", required = false) String followStaffUid,
            @ApiParam(value = "幼儿园：小:-3，中:-2，大-1；小学：一:1，二:2，三:3，四:4，五:5，六:6；初中：初一:7，初二:8；未知:0")
            @RequestParam(value = "grade", required = false) Integer grade,
            @ApiParam(value = "会员类型 1.无服务会员 2.体验会员 3.正式会员 4.过期会员") @RequestParam(value = "memberType", required = false) Integer memberType,
            @ApiParam(value = "客户来源") @RequestParam(value = "customSource", required = false) String customSource,
            @ApiParam(value = "异业渠道") @RequestParam(value = "channelUid", required = false) String channelUid
    ) throws Exception {
        // 获取员工信息
        R<Object> result = LoginInfoUtil.getLoginDto(request);
        if (result.getSt() != 0) throw new DescribeException(500, result.getMsg());
        LoginDataDto loginDto = (LoginDataDto) result.getData();

        if (!AccountUtil.isStoreManager(loginDto.getStoreRoles()))
            throw new DescribeException("非店长账号，不能操作");

        String today = DateUtil.getNowDateStr();
        List<String> orderTypes = Lists.newArrayList(EnumType.OrderType.EXP.getType(), EnumType.OrderType.GIFT.getType());

        List<Members> list = membersMapper.listByType(storeUid, keyword, followStaffUid, grade, memberType, customSource, channelUid, today, orderTypes);
        if (CollectionUtils.isEmpty(list))
            throw new DescribeException("未查询到会员信息");

        List<MemberVO> voList = new ArrayList<>();
        for (Members members : list) {
            MemberVO vo = new MemberVO();
            vo.setMob(members.getMob());
            vo.setName(members.getFullName());
            vo.setGrade(MemberUtil.getGrade(members.getGrade()));
            String source = MemberUtil.getCutomSource(members.getCustomSource());
            if (StringUtils.isNotBlank(members.getChannelName()))
                source += "-" + members.getChannelName();
            vo.setCustomSource(source);
            vo.setRefererMemberName(members.getRefererMemberName());
            vo.setRefererStaffName(members.getRefererStaffName());

            voList.add(vo);
        }

        String fileName = "会员信息";
        ExcelHandler.exportExcel(response, voList, MemberVO.class, fileName, "会员信息", true);
    }

    /**
     * 根据渠道下的产品包，创建会员订单、服务、跟进记录
     */
    private Cmorders newMemberOrderAndServices(
            List<Cmservices> newServiceList, String corpUid, String storeUid, String storeName, String memberUid, String memberName,
            Staff staff, String staffUid, String staffName, String channelProductUid, String remark
    ) throws Exception {
        StoreProducts products = storeProductsService.getByStoreUidOrUid(storeUid, channelProductUid);
        if (null != products) {
            List<StoreProductLogs> logs = productLogsService.listByStoreUidAndProductUid(storeUid, channelProductUid);
            if (CollectionUtils.isNotEmpty(logs)) {
                // 获取服务信息
                List<String> projectUids = logs.stream().map(StoreProductLogs::getProjectUid).collect(Collectors.toList());
                List<StoreProjects> projectsList = storeProjectsService.listByUids(projectUids);
                Map<String, StoreProjects> projectsMap = null;
                if (CollectionUtils.isEmpty(projectsList))
                    throw new DescribeException(500, "产品的服务信息获取失败");

                projectsMap = projectsList.stream().collect(Collectors.toMap(StoreProjects::getUid, Function.identity()));

                // 引流产品，订单类型是体验会员，服务是非赠送
                String orderType = EnumType.OrderType.EXP.getType();
                // 创建会员订单
                String orderDate = DateUtil.getCurrentDate();
                Cmorders cmorders = CmorderUtil.newOrderByProducts(corpUid, storeUid, storeName, memberUid, memberName,
                        staff, staffUid, staffName, orderType, orderDate, remark);
                cmorders.setServiceNum(logs.size());

                // 创建会员服务
                for (StoreProductLogs log : logs) {
                    Cmservices service = CmorderUtil.newServiceByProductLogs(corpUid, storeUid, storeName, memberUid, memberName,
                            staffUid, staffName, cmorders.getOrderCode(), orderType, 0, remark, log, projectsMap);
                    newServiceList.add(service);
                }

                return cmorders;
            }
        }
        return null;
    }

    @ApiOperation(value = "小程序登陆验证")
    @PostMapping(value = "/xcxLogin")
    public R<Object> xcxLogin(
            @ApiParam(value = "手机号") @RequestParam(value = "phone") String phone
    ) {
        List<Members> membersList = membersService.getByPhone(phone);
        List<Members> members = new ArrayList<>();
        if (CollectionUtils.isEmpty(membersList))
            return R.ok();
        for (Members member : membersList) {
            String memberUid = member.getUid();
            List<Cmservices> cmservicesList = cmservicesService.getByMemberUid(memberUid);
            double totalActivateAmount = 0d;
            for (Cmservices cmservices : cmservicesList) {
                totalActivateAmount += NepUtil.nullToZero(cmservices.getActivateAmount());
            }
            if (totalActivateAmount <= 0)
                continue;
            members.add(member);
        }
        return R.ok(members);
    }

    @ApiOperation(value = "批量设置市场人员")
    @PostMapping(value = "/setReferer", produces = "application/json; charset=UTF-8")
    public R<Object> setReferer(
            @ApiParam(value = "公司uid") @RequestParam(value = "corpUid") String corpUid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "员工uid") @RequestParam(value = "staffUid") String staffUid,
            @ApiParam(value = "员工名") @RequestParam(value = "staffName") String staffName,
            @ApiParam(value = "会员uid集合") @RequestParam(value = "uids") List<String> uids,
            @ApiParam(value = "市场人员uid") @RequestParam(value = "refererStaffUid") String refererStaffUid
    ) {
        return membersService.setReferer(corpUid, storeUid, storeName, staffUid, staffName, uids, refererStaffUid);
    }

}